local cyrillic = {}


function cyrillic.sub(str, first, last)
    local indexStart, indexEnd, result

    if not last then last = first end

    indexStart = cyrillic.getIndexOfChar(str, first)
    indexEnd = cyrillic.getIndexOfChar(str, last)
    if not indexEnd then
        indexEnd = cyrillic.len(str)
    end
    result = ''

    if (indexStart and indexEnd) then
        if (string.byte(str, indexEnd) > 191) then
            indexEnd = indexEnd + 1
        end
        return string.sub(str, indexStart, indexEnd)
    end
    return result
end


-- TODO remove
--function cyrillic.len(str)
--    local _, count = string.gsub(str, '[^\128-\193]', '')
--    return count
--end

function cyrillic.len(str)
    local chars, length, finish
    chars = 0
    index = 1
    length = string.len(str)
    finish = false

    repeat
        if not string.byte(str, index) then
            finish = true
        else
            if (string.byte(str, index) > 191) then
                index = index + 1
            end
            index = index + 1
            chars = chars + 1
        end
    until finish

    return chars
end


-- TODO remove
---- Return the character count in a unicode string word
--function wordLength(word)
--    local wordlength = 0
--    for c in string.gmatch(word, ".") do
--        if( string.byte(c)  < 128 or string.byte(c) > 191) then 
--            --print("c  "..string.byte(c))
--            wordlength = wordlength + 1
--        end
--    end
--    return wordlength
--end




function cyrillic.getIndexOfChar(str, letter)
    local index, currentLetter
    index = 1
    currentLetter = 1
    local finish = false

    repeat
        if not string.byte(str, index) then
            index = nil
            finish = true
        else
            if letter == currentLetter then
                finish = true
            else
                currentLetter = currentLetter + 1
                if (string.byte(str, index) > 191) then
                    index = index + 2
                else
                    index = index + 1
                end
            end
        end
    until finish

    return index
end


function cyrillic.isCyrillic(str)
    -- if(W[0]<0x0400 || W[0]>0x0451) return false; //не кирилица!
    -- TODO fix
    -- проверка первого символа на кириллицу
    local firstChar = cyrillic.getChar(str, 1)
    if (string.len(firstChar) == 1) then
        return false
    end
    return true
end


-- TODO remove? unneded?
function cyrillic.isLatin(str)
    -- проверка первого символа на латинский алфавит
    local firstChar = cyrillic.getChar(str, 1)
    if (string.len(firstChar) == 1) then
        return true
    end
    return false
end


function cyrillic.isStringContainChar(str, char)
    -- TODO remove
    -- print('  isStringContainChar: ', str, char)
    -- возвращает true если строка str содержит символ char
    local result = false
    local len = cyrillic.len(str)
    local finish = false
    local index = 1
    repeat
        if cyrillic.getChar(str, index) == char then
            finish = true
            result = true
        end
        index = index + 1
        if index > len then
            finish = true
        end
    until finish
    return result
end


-- TODO remove unneeded?
function cyrillic.isStringContainAnyChar(str, strOfChars)
    -- возвращает true если строка str содержит любой из символов строки strOfChars
    local result = false
    local len = cyrillic.len(strOfChars)
    local finish = false
    local index = 1
    repeat
        local currentChar = cyrillic.getChar(strOfChars, index)
        result = cyrillic.isStringContainChar(str, currentChar)
--        print(index, currentChar, result, finish)
        index = index + 1
        if (index > len) or (result) then
            finish = true
        end
    until finish
    return result
end


function cyrillic.skipPrefixes(str)
    -- возвращает строку без префиксов @ и $
    -- пропускаем префиксы
    while ( (cyrillic.getChar(str, 1) == '@') or (cyrillic.getChar(str, 1) == '$') ) do
        local len
        len = cyrillic.len(str)
        -- вырезаем начиная со второго символа до конца строки
        str = cyrillic.sub(str, 2, len)
    end
    return str
end


-- TODO fix
function cyrillic.cp1251ToUtf8(s)
    local cp1251=
    {
--        [128]='\208\130',[129]='\208\131',[130]='\226\128\154',[131]='\209\147',[132]='\226\128\158',[133]='\226\128\166',
--        [134]='\226\128\160',[135]='\226\128\161',[136]='\226\130\172',[137]='\226\128\176',[138]='\208\137',[139]='\226\128\185',
--        [140]='\208\138',[141]='\208\140',[142]='\208\139',[143]='\208\143',[144]='\209\146',[145]='\226\128\152',
--        [146]='\226\128\153',[147]='\226\128\156',[148]='\226\128\157',[149]='\226\128\162',[150]='\226\128\147',[151]='\226\128\148',
--        [152]='\194\152',[153]='\226\132\162',[154]='\209\153',[155]='\226\128\186',[156]='\209\154',[157]='\209\156',
--        [158]='\209\155',[159]='\209\159',[160]='\194\160',[161]='\209\142',[162]='\209\158',[163]='\208\136',
--        [164]='\194\164',[165]='\210\144',[166]='\194\166',[167]='\194\167',[168]='\208\129',[169]='\194\169',
--        [170]='\208\132',[171]='\194\171',[172]='\194\172',[173]='\194\173',[174]='\194\174',[175]='\208\135',
--        [176]='\194\176',[177]='\194\177',[178]='\208\134',[179]='\209\150',[180]='\210\145',[181]='\194\181',
--        [182]='\194\182',[183]='\194\183',[184]='\209\145',[185]='\226\132\150',[186]='\209\148',[187]='\194\187',
--        [188]='\209\152',[189]='\208\133',[190]='\209\149',[191]='\209\151'
        [128]='\208\130', [129]='\208\131', [130]='\226\128\154',
        [131]='\209\147', [132]='\226\128\158', [133]='\226\128\166',
        [134]='\226\128\160', [135]='\226\128\161', [136]='\226\130\172',
        [137]='\226\128\176', [138]='\208\137', [139]='\226\128\185',
        [140]='\208\138', [141]='\208\140', [142]='\208\139',
        [143]='\208\143', [144]='\209\146', [145]='\226\128\152',
        [146]='\226\128\153', [147]='\226\128\156', [148]='\226\128\157',
        [149]='\226\128\162', [150]='\226\128\147', [151]='\226\128\148',
        [152]='\194\152', [153]='\226\132\162', [154]='\209\153',
        [155]='\226\128\186', [156]='\209\154', [157]='\209\156',
        [158]='\209\155', [159]='\209\159', [160]='\194\160',
        [161]='\209\142', [162]='\209\158', [163]='\208\136',
        [164]='\194\164', [165]='\210\144', [166]='\194\166',
        [167]='\194\167', [168]='\208\129', [169]='\194\169',
        [170]='\208\132', [171]='\194\171', [172]='\194\172',
        [173]='\194\173', [174]='\194\174', [175]='\208\135',
        [176]='\194\176', [177]='\194\177', [178]='\208\134',
        [179]='\209\150', [180]='\210\145', [181]='\194\181',
        [182]='\194\182', [183]='\194\183', [184]='\209\145',
        [185]='\226\132\150', [186]='\209\148', [187]='\194\187',
        [188]='\209\152', [189]='\208\133', [190]='\209\149', [191]='\209\151'
    }
    local r, b = ''
    for i = 1, s and s:len() or 0 do
        b = s:byte(i)
        if b < 128 then
            r = r..string.char(b)
        else
            if b > 239 then
                r = r..'\209'..string.char(b-112)
            elseif b > 191 then
                r = r..'\208'..string.char(b-48)
            elseif cp1251[b] then
                r = r..cp1251[b]
            else
                r = r..'_'
            end
        end
    end
    return r
end


function cyrillic.removeRepeatChars(str)
    -- возвращает строку без повторяющихся символов
    local result = ''
    local lastNewChar = ''
    for i = 1, cyrillic.len(str) do
        local char = cyrillic.sub(str, i, i)
        if (lastNewChar == '') or (lastNewChar ~= char) then
            -- первая буква в слове или неповторяющаяся
            result = result..char
            lastNewChar = char
        end
    end
    return result
end


-- возвращает окончание слова длиной number из строки str
function cyrillic.getRightChars(str, number)
    local result, ending, len
    result = ''
    len = cyrillic.len(str)
    result = cyrillic.sub(str, len - number + 1, len) -- +1 Lua?
    return result
end


function cyrillic.getChar(str, number)
    -- возвращает из строки str символ из позиции number
    local char = ''
    local len = cyrillic.len(str)
    if (number <= len) and (number > 0) then
        char = cyrillic.sub(str, number, number)
    end
    return char
end


function cyrillic.getCharFromRight(str, number)
    local char = ''
    local len = cyrillic.len(str)
    if (len - number + 1 > 0) then
        char = cyrillic.sub(str, len - number + 1, len - number + 1) -- + 1 Lua?
    end
    return char
end


function cyrillic.removeCharFromRight(str, number)
    -- возвращает строку str с удалёнными number символами справа
    local result, len, index
    result = ''
    len = cyrillic.len(str)
    index = len - number + 1 -- + 1 Lua
    for i = 1, len do
        if not (i == index) then
            result = result..cyrillic.sub(str, i, i)
        end
    end
    return result
end


function cyrillic.cutCharsFromRight(str, number)
    local result, len
    result = ''
    len = cyrillic.len(str)
    result = cyrillic.sub(str, 1, len - number) -- +1 Lua
    return result
end


-- TODO убрать?
function cyrillic.trimRightLeft(str)
    -- удаляет пробелы справа и слева, оставляя только буквы
    local tmp = ''
    tmp = str:gsub('^%s*(.-)%s*$', '%1')
    return tmp
end


function cyrillic.utf8ToCp1251(char)
    -- возвращает cp1251 код русской буквы в utf8
    -- возвращает признак ru = true если буква русская
    local result = string.byte(char, 1)
    local ru = false
    if (string.byte(char, 1) == 208) then
        if (string.byte(char, 2) >= 144) and (string.byte(char, 2) <= 191) then
            result = string.byte(char, 2) + 48
            ru = true
        end
    end
    if (string.byte(char, 1) == 209) then
        if (string.byte(char, 2) >= 128) and (string.byte(char, 2) <= 143) then
            result = string.byte(char, 2) + 112
            ru = true
        end
    end
    -- символы вне общего правила
    -- Ё utf8 208, 129 -> 168
    if ((string.byte(char, 1) == 208) and (string.byte(char, 2) == 129)) then
-- TODO fix
--        print('ЁЁЁЁЁЁЁЁЁЁЁ')
        result = 168
        ru = true
    end
    -- ё utf8 209, 145 -> 184
    if ((string.byte(char, 1) == 209) and (string.byte(char, 2) == 145)) then
-- TODO fix
--        print('ёёёёёёёёёёёёёёёёё')
        result = 184
        ru = true
    end
--    print('CODE='..result)
    return result, ru
end


function cyrillic.normalize(str)
    local result = str
    -- преобразуем строку в нижний регистр
    result = cyrillic.toLowerCase(result)
    -- заменяем все буквы ё -> е
    result = cyrillic.replaceCharToChar(result, 'ё', 'е')
    -- убираем знак ударения
    result = cyrillic.replaceCharToChar(result, '`', '')
    -- убираем двойные пробелы
    result = cyrillic.removeDoubleSpaces(result)
    return result
end


function cyrillic.replaceCharToChar(str, charOld, charNew)
    local result = ''
    local len = cyrillic.len(str)
    for i = 1, len do
        local curr = cyrillic.sub(str, i, i)
        if curr == charOld then
            result = result..charNew
        else
            result = result..curr
        end
    end
    return result
end


function cyrillic.toLowerCase(str)
    local chars =
    {
        ['А'] = 'а',
        ['Б'] = 'б',
        ['В'] = 'в',
        ['Г'] = 'г',
        ['Д'] = 'д',
        ['Е'] = 'е',
        ['Ё'] = 'ё',
        ['Ж'] = 'ж',
        ['З'] = 'з',
        ['И'] = 'и',
        ['Й'] = 'й',
        ['К'] = 'к',
        ['Л'] = 'л',
        ['М'] = 'м',
        ['Н'] = 'н',
        ['О'] = 'о',
        ['П'] = 'п',
        ['Р'] = 'р',
        ['С'] = 'с',
        ['Т'] = 'т',
        ['У'] = 'у',
        ['Ф'] = 'ф',
        ['Х'] = 'х',
        ['Ц'] = 'ц',
        ['Ч'] = 'ч',
        ['Ш'] = 'ш',
        ['Щ'] = 'щ',
        ['Ъ'] = 'ъ',
        ['Ы'] = 'ы',
        ['Ь'] = 'ь',
        ['Э'] = 'э',
        ['Ю'] = 'ю',
        ['Я'] = 'я',

        ['A'] = 'a',
        ['B'] = 'b',
        ['C'] = 'c',
        ['D'] = 'd',
        ['E'] = 'e',
        ['F'] = 'f',
        ['G'] = 'g',
        ['H'] = 'h',
        ['I'] = 'i',
        ['J'] = 'j',
        ['K'] = 'k',
        ['L'] = 'l',
        ['M'] = 'm',
        ['N'] = 'n',
        ['O'] = 'o',
        ['P'] = 'p',
        ['Q'] = 'q',
        ['R'] = 'r',
        ['S'] = 's',
        ['T'] = 't',
        ['U'] = 'u',
        ['V'] = 'v',
        ['W'] = 'w',
        ['X'] = 'x',
        ['Y'] = 'y',
        ['Z'] = 'z',
    }
    local result = ''
    local len = cyrillic.len(str)
    for i = 1, len do
        local ch, curr
        curr = cyrillic.sub(str, i, i)
        if chars[curr] then
            result = result..chars[curr]
        else
            result = result..curr
        end
    end
    return result
end


function cyrillic.removeDoubleSpaces(str)
    local result = ''
    local space = false
    local len = cyrillic.len(str)
    for i = 1, len do
        local curr = cyrillic.sub(str, i, i)
        if curr == ' ' then
            if not space then
                result = result..' '
            end
            space = true
        else
            space = false
            result = result..curr
        end
    end
    return result
end


function cyrillic.cp1251GetStringTilChar(str, charEnd)
    local result = ''
-- TODO fix
--    print('ORG='..str)
    local len = string.len(str)
    for i = 1, len do
        local char = string.sub(str, i, i)
        if (char == charEnd) then
            break
        end
        result = result..char
    end
--    print('RES='..result..'%')
--    print(cyrillic.cp1251ToUtf8(result))
    return result
end


return cyrillic
